package com.vv.tools.modules.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vv.tools.common.constant.sys.UserStatusEnum;
import com.vv.tools.common.message.CustomerBizException;
import com.vv.tools.common.message.ResultEnum;
import com.vv.tools.common.util.PageUtil;
import com.vv.tools.common.util.TraceOp;
import com.vv.tools.modules.sys.converter.UserConvert;
import com.vv.tools.modules.sys.dao.UserMapper;
import com.vv.tools.modules.sys.entity.User;
import com.vv.tools.modules.sys.entity.UserRole;
import com.vv.tools.modules.sys.model.UserDTO;
import com.vv.tools.modules.sys.service.UserRoleService;
import com.vv.tools.modules.sys.service.UserService;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import lombok.AllArgsConstructor;

import org.apache.commons.codec.digest.Sha2Crypt;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import static com.vv.tools.common.constant.base.Constant.SUPER_ADMIN;

/**
 * <p>
 * 系统用户 服务实现类
 * </p>
 *
 * @author vv
 * @since 2025-02-19
 */
@Service
@AllArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final UserRoleService userRoleService;

    private static void checkSuperAdmin(Long id) {
        if (SUPER_ADMIN.equals(id)) {
            throw new CustomerBizException(ResultEnum.SUPER_ADMIN_NOT_DELETE);
        }
    }

    @Override
    public User getByUsername(String username) {
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
            .eq(User::getUsername, username)
            .eq(User::getStatus, UserStatusEnum.VALID.getCode());
        return baseMapper.selectOne(wrapper);
    }

    @Override
    public boolean addUser(UserDTO userDTO) {
        // 用户名重复校验
        User dbUser = baseMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getUsername, userDTO.getUsername()));
        if (null != dbUser) {
            throw new CustomerBizException(ResultEnum.USERS_USERNAME_REPEAT);
        }

        User user = UserConvert.INSTANCE.dto2do(userDTO);
        user.setId(null);

        // 盐 & 密码加密
        String salt = "$5$" + RandomStringUtils.randomAlphanumeric(8);
        user.setSalt(salt);
        user.setPassword(Sha2Crypt.sha256Crypt(user.getPassword().getBytes(StandardCharsets.UTF_8), salt));

        // 有效状态
        user.setStatus(UserStatusEnum.VALID.getCode());

        return this.save(user) && isSaveRole(userDTO.getRoles(), user.getId());
    }

    @Override
    public boolean updateUser(UserDTO userDTO) {
        // 用户是否存在
        User checkUser = baseMapper.selectById(userDTO.getId());
        if (null == checkUser) {
            throw new CustomerBizException(ResultEnum.USERS_USER_NOT_EXIST);
        }

        checkSuperAdmin(userDTO.getId());

        User user = UserConvert.INSTANCE.dto2do(userDTO);
        // 用户名不能修改
        user.setUsername(null);
        if (StringUtils.isNotBlank(user.getPassword())) {
            user.setPassword(Sha2Crypt.sha256Crypt(user.getPassword().getBytes(StandardCharsets.UTF_8), checkUser.getSalt()));
        }
        return this.updateById(user) && isSaveRole(userDTO.getRoles(), user.getId());
    }

    @Override
    public boolean deleteUser(Long id) {
        checkSuperAdmin(id);

        if (id.equals(TraceOp.getUserId())) {
            throw new CustomerBizException(ResultEnum.USERS_CUR_USER_NOT_DELETE);
        }

        return this.removeById(id);
    }

    @Override
    public Page<UserDTO> page(UserDTO userDTO) {
        PageUtil<User> pu = new PageUtil<>(userDTO);
        Page<UserDTO> mapper = pu.of(baseMapper).query(Wrappers.lambdaQuery(User.class)
                .eq(StringUtils.isNotBlank(userDTO.getUsername()), User::getUsername, userDTO.getUsername()))
            .mapper(UserConvert.INSTANCE::do2dto);
        Set<Long> uids = mapper.getRecords().stream().map(UserDTO::getId).collect(Collectors.toSet());
        List<UserRole> urList = userRoleService.list(Wrappers.lambdaQuery(UserRole.class).in(UserRole::getUserId, uids));
        if (CollectionUtils.isNotEmpty(urList)) {
            Map<Long, List<UserRole>> urMap = urList.stream().collect(Collectors.groupingBy(UserRole::getUserId));
            for (UserDTO dto : mapper.getRecords()) {
                if (urMap.containsKey(dto.getId())) {
                    dto.setRoles(urMap.get(dto.getId()).stream().map(UserRole::getRoleId).map(String::valueOf).collect(Collectors.toList()));
                }
            }
        }
        return mapper;
    }

    private boolean isSaveRole(List<String> roles, Long userId) {
        // 新增角色
        boolean saveRole = false;
        if (CollectionUtils.isNotEmpty(roles)) {
            // 先判断角色是否一致
            LambdaQueryWrapper<UserRole> eq = Wrappers.lambdaQuery(UserRole.class).eq(UserRole::getUserId, userId);
            List<UserRole> urList = userRoleService.list(eq);
            Set<String> rs = urList.stream().map(UserRole::getRoleId).map(String::valueOf).collect(Collectors.toSet());
            boolean equalCollection = CollectionUtils.isEqualCollection(rs, roles);
            if (equalCollection) {
                return true;
            }
            // 不一致就先批量删除，在批量保存
            userRoleService.remove(eq);
            List<UserRole> list = new ArrayList<>();
            for (String roleId : roles) {
                UserRole ur = new UserRole();
                ur.setUserId(userId);
                ur.setRoleId(Long.valueOf(roleId));
                list.add(ur);
            }
            saveRole = userRoleService.saveBatch(list);
        }
        return saveRole;
    }

}
